#-*- coding:utf-8 -*-

from flask import Flask
from flasgger import Swagger
from flask import request, jsonify
from logging_settings import load_my_logging_cfg
from kg_server import KGServer
from datetime import datetime as dt
import json

app = Flask(__name__)
Swagger(app)
logger = load_my_logging_cfg()

@app.route('/kg/node/delete',methods=['POST'])
def kg_node_delete():
    """
            实体节点删除接口
            ---
            tags:
              - 相关删除接口
            consumes:
              - "multipart/form-data"
            produces:
              - "application/json"
            parameters:
              - name: "uuid"
                in: "formData"
                description: "节点唯一标识"
                required: true
                type: "string"
            responses:
              1:
                  description: 删除成功


                  example: {'code':1,
                            'message':Success',
                            'data':{
                              'nodes':[{
                                'k1':v1,
                                'k2':v2,
                                ...
                              }],
                              'edges':[]
                              }
                            }
              2:
                description: 查询失败,缺少有效的参数
              3:
                description: 查询失败,语法错误
              4:
                description: 没有匹配数据
            """
    data = {
        'code': 1,
        'msg': 'Success',
        'data': {
            'nodes': [],
            'edges': []
        }
    }
    uuid = request.form.get('uuid')
    if not uuid:
        data['code'] = 2
        data['msg'] = '缺少有效的参数'
        return jsonify(data)
    kg_server = KGServer()
    try:
        kg_server.select("MATCH (n {uuid:'%s'}) delete n"%uuid)
        node_data = kg_server.select("MATCH (n {uuid:'%s'}) return n"%uuid).data()
        if node_data:
            data['code'] = 2
            data['msg'] = '不能删除改节点,该节点存在关系'
    except Exception as e:
        data['code'] = 2
        data['msg'] = str(e)
    return jsonify(data)

@app.route('/kg/edge/delete',methods=['POST'])
def kg_edge_delete():
    """
            关系删除接口
            ---
            tags:
              - 相关删除接口
            consumes:
              - "multipart/form-data"
            produces:
              - "application/json"
            parameters:
              - name: "start_node_uuid"
                in: "formData"
                description: "开始节点uuid"
                required: true
                type: "string"
              - name: "end_node_uuid"
                in: "formData"
                description: "结束节点uuid"
                required: true
                type: "string"
              - name: "relation_type"
                in: "formData"
                description: "关系类型"
                required: true
                type: "string"
              - name: "id"
                in: "formData"
                description: "边的唯一id"
                required: false
                type: "string"
            responses:
              1:
                  description: 删除成功


                  example: {'code':1,
                            'message':Success',
                            'data':{
                              'nodes':[{
                                'k1':v1,
                                'k2':v2,
                                ...
                              }],
                              'edges':[]
                              }
                            }
              2:
                description: 查询失败,缺少有效的参数
              3:
                description: 查询失败,语法错误
              4:
                description: 没有匹配数据
            """
    data = {
        'code': 1,
        'msg': 'Success',
        'data': {
            'nodes': [],
            'edges': []
        }
    }
    if not request.form or not request.form.get('start_node_uuid') or \
            not request.form.get('end_node_uuid') or \
            not request.form.get('relation_type'):
        data['code'] = 2
        data['msg'] = '缺少有效的参数'
        return jsonify(data)
    kg_server = KGServer()
    form_data = request.form.to_dict()
    start_node_uuid = form_data.pop('start_node_uuid')
    end_node_uuid = form_data.pop('end_node_uuid')
    relation_type = form_data.pop('relation_type')
    if 'id' in form_data:
        rid = form_data.pop('id')
        cypter_del_str = "MATCH (s)-[r]->(e) WHERE id(r)=%s delete r"%rid
        cypter_str = "MATCH p=(s)-[r]->(e) WHERE id(r)=%s RETURN p" % rid
    else:
        cypter_del_str = "MATCH (s {uuid:'%s'})-[r:%s]->(e {uuid:'%s'}) delete r" % (start_node_uuid, relation_type, end_node_uuid)
        cypter_str = "MATCH p=(s {uuid:'%s'})-[r:%s]->(e {uuid:'%s'}) RETURN p" % (
        start_node_uuid, relation_type, end_node_uuid)
    try:
        kg_server.select(cypter_del_str)
        res = kg_server.select(cypter_str).data()
        if res:
            data['code'] = 2
            data['msg'] = '删除关系失败'
            logger.error(cypter_del_str+'&&&'+cypter_str)
    except Exception as e:
        data['code'] = 2
        data['msg'] = str(e)
        logger.error(e)
        return jsonify(data)

    logger.info(cypter_str)


    return jsonify(data)

@app.route('/kg/node/update',methods=['POST'])
def kg_node_update():
    """
            实体节点更新接口
            ---
            tags:
              - 相关更新接口
            consumes:
              - "multipart/form-data"
            produces:
              - "application/json"
            parameters:
              - name: "uuid"
                in: "formData"
                description: "节点的唯一标识"
                required: true
                type: "string"
              - name: "any_key1"
                in: "formData"
                description: "节点待更新属性"
                required: false
                type: "string"
              - name: "any_key2"
                in: "formData"
                description: "节点待更新属性"
                required: true
                type: "string"
            responses:
              1:
                  description: 更新成功


                  example: {'code':1,
                            'message':Success',
                            'data':{
                              'nodes':[{
                                'k1':v1,
                                'k2':v2,
                                ...
                              }],
                              'edges':[]
                              }
                            }
              2:
                description: 查询失败,缺少有效的参数
              3:
                description: 查询失败,语法错误
              4:
                description: 没有匹配数据
            """
    data = {
        'code': 1,
        'msg': 'Success',
        'data': {
            'nodes': [],
            'edges': []
        }
    }
    if not request.form or not request.form.get('uuid'):
        data['code'] = 2
        data['msg'] = '缺少有效的参数'
        return jsonify(data)
    kg_server = KGServer()
    form_data = request.form.to_dict()
    uuid = form_data.get('uuid')
    try:
        node_obj = kg_server.select("MATCH (n {uuid:'%s'}) return n"%uuid).data()
        node_label = list(node_obj[0]['n'].labels)[0]
        node_pro_dic = dict(node_obj[0]['n'].items())
    except Exception as e:
        # print(e)
        data['code'] = 2
        data['msg'] = '该节点不存在'
        return data
    if 'label' in form_data:
        new_label = form_data.pop('label')
        if new_label != node_label:
            cypher_change_label_cmd = "MATCH (n {uuid:'%s'}) SET n:%s REMOVE n:%s  RETURN n"%(uuid,new_label,node_label)
        # print(cypher_change_label_cmd)
            kg_server.select(cypher_change_label_cmd)
            logger.info(cypher_change_label_cmd)
    for k,v in form_data.items():
        node_pro_dic[k] = v
    args = kg_server.dic2args(node_pro_dic)
    cypher_change_pro_cmd = "MATCH (n {uuid:'%s'}) SET n=%s RETURN n"%(uuid,args)
    res = kg_server.select(cypher_change_pro_cmd).data()
    if res:
        node_data = kg_server.node_handel(res[0]['n'])
        data['data']['nodes'].append(node_data)
    else:
        data['code'] = 2
        data['msg'] = '修改失败'
    logger.info(cypher_change_pro_cmd)
    return jsonify(data)

@app.route('/kg/edge/update',methods=['POST'])
def kg_edge_update():
    """
            关系更新接口
            ---
            tags:
              - 相关更新接口
            consumes:
              - "multipart/form-data"
            produces:
              - "application/json"
            parameters:
              - name: "start_node_uuid"
                in: "formData"
                description: "开始节点uuid"
                required: true
                type: "string"
              - name: "end_node_uuid"
                in: "formData"
                description: "结束节点uuid"
                required: true
                type: "string"
              - name: "relation_type"
                in: "formData"
                description: "关系类型"
                required: true
                type: "string"
              - name: "new_rel_type"
                in: "formData"
                description: "待更新的关系类型"
                required: false
                type: "string"
              - name: "id"
                in: "formData"
                description: "边的唯一id"
                required: false
                type: "string"
              - name: "any_key1"
                in: "formData"
                description: "待更新关系属性"
                required: false
                type: "string"
              - name: "any_key2"
                in: "formData"
                description: "待更新关系属性"
                required: false
                type: "string"
            responses:
              1:
                  description: 更新成功


                  example: {'code':1,
                            'message':Success',
                            'data':{
                              'nodes':[{
                                'k1':v1,
                                'k2':v2,
                                ...
                              }],
                              'edges':[]
                              }
                            }
              2:
                description: 查询失败,缺少有效的参数
              3:
                description: 查询失败,语法错误
              4:
                description: 没有匹配数据
            """
    data = {
        'code': 1,
        'msg': 'Success',
        'data': {
            'nodes': [],
            'edges': []
        }
    }
    if not request.form or not request.form.get('start_node_uuid') or \
            not request.form.get('end_node_uuid') or \
            not request.form.get('relation_type'):
        data['code'] = 2
        data['msg'] = '缺少有效的参数'
        return jsonify(data)
    kg_server = KGServer()
    form_data = request.form.to_dict()
    start_node_uuid = form_data.pop('start_node_uuid')
    end_node_uuid = form_data.pop('end_node_uuid')
    relation_type = form_data.pop('relation_type')
    new_rel_type = form_data.pop('new_rel_type') if 'new_rel_type' in form_data else None
    if 'id' in form_data:
        rid = form_data.pop('id')
        cypter_str = "MATCH p=(s)-[r]->(e) WHERE id(r)=%s RETURN p"%rid
    else:
        cypter_str = "MATCH p=(s {uuid:'%s'})-[r:%s]->(e {uuid:'%s'}) RETURN p" % (start_node_uuid, relation_type, end_node_uuid)
    try:
        # print(cypter_str)
        res = kg_server.select(cypter_str)
    except Exception as e:
        data['code'] = 2
        data['msg'] = str(e)
        logger.error(e)
        return jsonify(data)
    data_obj = res.data()
    if data_obj:
        rel = data_obj[0]['p'].relationships[0]
        rel_data = kg_server.rel_handel(rel)
        rel_pro = rel_data['properties']
        if new_rel_type:
            kg_server.select("MATCH (s {uuid:'%s'})-[r:%s]->(e {uuid:'%s'}) CREATE (s)-[r2:%s]->(e) SET r2=r WITH r DELETE r"%(start_node_uuid,relation_type,end_node_uuid,new_rel_type))
            relation_type = new_rel_type
        for k,v in form_data.items():
            rel_pro[k] = v
        # print(rel_pro)
        args = kg_server.dic2args(rel_pro)
        rel_data = kg_server.select("MATCH p=(s {uuid:'%s'})-[r:%s]->(e {uuid:'%s'}) SET r=%s RETURN p"%(start_node_uuid,relation_type,end_node_uuid,args)).data()
        if rel_data:
            rel_l = data_obj[0]['p'].relationships
            node_l = data_obj[0]['p'].nodes

            for rel in rel_l:
                data['data']['edges'].append(kg_server.rel_handel(rel))
            for node in node_l:
                data['data']['nodes'].append(kg_server.node_handel(node))
        if not data['data']['edges']:
            data['code'] = 3
            data['msg'] = '没有查询到相关数据'
        logger.info(cypter_str)


    return jsonify(data)

@app.route('/kg/node/insert',methods=['POST'])
def kg_node_insert():
    """
            实体节点插入接口
            ---
            tags:
              - 相关插入接口
            consumes:
              - "multipart/form-data"
            produces:
              - "application/json"
            parameters:
              - name: "label"
                in: "formData"
                description: "节点标签"
                required: true
                type: "string"
              - name: "uuid"
                in: "formData"
                description: "节点唯一标识"
                required: true
                type: "string"
              - name: "any_key1"
                in: "formData"
                description: "节点属性,不限个数"
                required: false
                type: "string"
              - name: "any_key2"
                in: "formData"
                description: "节点属性,不限个数"
                required: false
                type: "string"
              - name: "any_key3"
                in: "formData"
                description: "节点属性,不限个数"
                required: false
                type: "string"
            responses:
              1:
                  description: 插入成功


                  example: {'code':1,
                            'message':Success',
                            'data':{
                              'nodes':[{
                                'k1':v1,
                                'k2':v2,
                                ...
                              }],
                              'edges':[]
                              }
                            }
              2:
                description: 查询失败,缺少有效的参数
              3:
                description: 查询失败,语法错误
              4:
                description: 没有匹配数据
            """
    data = {
        'code': 1,
        'msg': 'Success',
        'data': {
            'nodes': [],
            'edges': []
        }
    }
    if not request.form or not request.form.get('uuid') or not request.form.get('label'):
        data['code'] = 2
        data['msg'] = '缺少有效的参数'
        return jsonify(data)
    kg_server = KGServer()
    form_data = request.form.to_dict()
    label = form_data.pop('label')
    uuid = form_data.get('uuid')
    form_data['created_time'] = dt.now().strftime("%Y-%m-%d %X")
    if kg_server.node_is_exist(uuid):
        data['msg'] = '该节点uuid已经存在,不能重复创建'
        data['code'] = 2
        return jsonify(data)
    args = kg_server.dic2args(form_data)
    cypter_str = "CREATE (n:{label} {args}) return n".format(label=label,args=args)
    node_data = kg_server.create_node(cypter_str)
    if node_data:
        data['data']['nodes'].append(node_data)
        logger.info(cypter_str)
    else:
        data['code'] = 2
        data['msg'] = '节点创建失败,cypher:{cypter_str}'.format(cypter_str=cypter_str)
        logger.error('cypher-->:{cypter_str} create error'.format(cypter_str=cypter_str))

    return jsonify(data)

@app.route('/kg/edge/insert',methods=['POST'])
def kg_edge_insert():
    """
            关系插入接口
            ---
            tags:
              - 相关插入接口
            consumes:
              - "multipart/form-data"
            produces:
              - "application/json"
            parameters:
              - name: "start_node_uuid"
                in: "formData"
                description: "开始节点uuid"
                required: true
                type: "string"
              - name: "end_node_uuid"
                in: "formData"
                description: "结束节点uuid"
                required: true
                type: "string"
              - name: "relation_type"
                in: "formData"
                description: "关系类型"
                required: true
                type: "string"
              - name: "any_key1"
                in: "formData"
                description: "关系属性,不限个数"
                required: false
                type: "string"
              - name: "any_key2"
                in: "formData"
                description: "关系属性,不限个数"
                required: false
                type: "string"
              - name: "any_key3"
                in: "formData"
                description: "关系属性,不限个数"
                required: false
                type: "string"
            responses:
              1:
                  description: 插入成功


                  example: {'code':1,
                            'message':Success',
                            'data':{
                              'nodes':[{
                                'k1':v1,
                                'k2':v2,
                                ...
                              }],
                              'edges':[]
                              }
                            }
              2:
                description: 查询失败,缺少有效的参数
              3:
                description: 查询失败,语法错误
              4:
                description: 没有匹配数据
            """
    data = {
        'code': 1,
        'msg': 'Success',
        'data': {
            'nodes': [],
            'edges': []
        }
    }
    if not request.form or not request.form.get('start_node_uuid') or \
            not request.form.get('end_node_uuid') or \
            not request.form.get('relation_type'):
        data['code'] = 2
        data['msg'] = '缺少有效的参数'
        return jsonify(data)
    kg_server = KGServer()
    form_data = request.form.to_dict()
    st_uuid = form_data.pop('start_node_uuid')
    en_uuid = form_data.pop('end_node_uuid')
    rel_type = form_data.pop('relation_type')
    form_data['created_time'] = dt.now().strftime("%Y-%m-%d %X")
    args = kg_server.dic2args(form_data)

    if kg_server.node_is_exist(st_uuid) and kg_server.node_is_exist(en_uuid):
        rel_data = kg_server.rel_is_exist(st_uuid,en_uuid,rel_type)
        if rel_data:
            data['msg'] = '已存在关系'
            data['data']['edges'].append(rel_data)
        else:
            cypter_str = "MATCH (s),(e) WHERE s.uuid='%s' AND e.uuid='%s' CREATE (s)-[r:%s %s] ->(e) RETURN r"%(
                st_uuid,en_uuid,rel_type,args
            )
            rel_data = kg_server.create_rel(cypter_str)
            rel_data['start_node_uuid'] = st_uuid
            rel_data['end_node_uuid'] = en_uuid
            data['data']['edges'].append(rel_data)
    else:
        data['msg'] = '起始节点或结束节点不存在'
        data['code'] = 2
    return jsonify(data)

@app.route('/kg/node/query',methods=['POST'])
def kg_node_query():
    """
            node节点精确查询
            ---
            tags:
              - 相关查询接口
            consumes:
              - "multipart/form-data"
            produces:
              - "application/json"
            parameters:
              - name: "label"
                in: "formData"
                description: "节点标签"
                required: false
                type: "string"
              - name: "uuid"
                in: "formData"
                description: "节点唯一标识"
                required: false
                type: "string"
              - name: "any_key1"
                in: "formData"
                description: "节点属性,不限个数"
                required: false
                type: "string"
              - name: "any_key2"
                in: "formData"
                description: "节点属性,不限个数"
                required: false
                type: "string"
            responses:
              1:
                  description: 查询成功


                  example: {'code':1,
                            'message':Success',
                            'data':{
                              'nodes':[{
                                'k1':v1,
                                'k2':v2,
                                ...
                              }],
                              'edges':[]
                              }
                            }
              2:
                description: 查询失败,缺少有效的参数
              3:
                description: 查询失败,语法错误
              4:
                description: 没有匹配数据
            """
    data = {
        'code':1,
        'msg':'Success',
        'data':{
            'nodes':[],
            'edges':[]
        }
    }
    if not request.form:
        data['code'] = 2
        data['msg'] = '缺少有效的参数'
        return jsonify(data)
    kg_server = KGServer()
    form_data = request.form.to_dict()
    if 'uuid' in form_data:
        # cypter_str = 'MATCH (n) WHERE id(n)=%s RETURN n'%int(form_data['uuid'])
        cypter_str = "MATCH (n {uuid:'%s'}) RETURN n"%form_data['uuid']
    else:
        if 'label' in form_data:
            label = form_data.pop('label')
            args = KGServer.dic2args(form_data)
            cypter_str = 'MATCH (n:{label} {args}) RETURN n'.format(label=label,args=args)
            # print(cypter_str)

        else:
            args = KGServer.dic2args(form_data)
            cypter_str = 'MATCH (n {args}) RETURN n'.format(args=args)
    try:
        res = kg_server.select(cypter_str)
    except Exception as e:
        data['code'] = 3
        data['msg'] = e
        logger.error(e)
        return jsonify(data)
    for record in res:
        node_data = kg_server.record2properties(record)
        # print(node_data)
        data['data']['nodes'].append(node_data)
        # print(data)
    if not data['data']['nodes']:
        data['code'] = 4
        data['msg'] = '没有查询到相关数据'
    logger.info(cypter_str)
    return jsonify(data)

@app.route('/kg/node/fuzzy_query',methods=['POST'])
def kg_node_fuzzy_query():
    """
            node节点模糊查询
            ---
            tags:
              - 相关查询接口
            consumes:
              - "multipart/form-data"
            produces:
              - "application/json"
            parameters:
              - name: "label"
                in: "formData"
                description: "节点标签"
                required: false
                type: "string"
              - name: "limit"
                in: "formData"
                description: "返回条数,默认为25条"
                required: false
                type: "string"
              - name: "any_key1"
                in: "formData"
                description: "节点属性,不限个数"
                required: false
                type: "string"
              - name: "any_key2"
                in: "formData"
                description: "节点属性,不限个数"
                required: false
                type: "string"
              - name: "any_key3"
                in: "formData"
                description: "节点属性,不限个数"
                required: false
                type: "string"
            responses:
              1:
                  description: 查询成功


                  example: {'code':1,
                            'message':Success',
                            'data':{
                              'nodes':[{
                                'k1':v1,
                                'k2':v2,
                                ...
                              }],
                              'edges':[]
                              }
                            }
              2:
                description: 查询失败,缺少有效的参数
              3:
                description: 查询失败,语法错误
              4:
                description: 没有匹配数据
            """
    data = {
        'code': 1,
        'msg': 'Success',
        'data': {
            'nodes': [],
            'edges': []
        }
    }
    kg_server = KGServer()
    form_data = request.form.to_dict()
    arg = None
    cypter_str = None
    label = form_data.pop('label') if 'label' in form_data else None
    limit = form_data.pop('limit') if 'limit' in form_data else '25'
    if form_data:
        arg = KGServer.dic2str(form_data)
    if label and arg:
        cypter_str = 'MATCH (n:{label}) WHERE {arg} RETURN n LIMIT {limit}'.format(label=label,arg=arg, limit=limit)
    elif not label and not arg:
        cypter_str = 'MATCH (n) RETURN n LIMIT {limit}'.format(limit=limit)
    elif not label and arg:
        cypter_str = 'MATCH (n) WHERE {arg} RETURN n LIMIT {limit}'.format(arg=arg,limit=limit)
    elif label and not arg:
        cypter_str = 'MATCH (n:{label}) RETURN n LIMIT {limit}'.format(label=label,limit=limit)
    try:
        res = kg_server.select(cypter_str)
    except Exception as e:
        data['code'] = 2
        data['msg'] = e
        logger.error(e)
        return jsonify(data)
    for record in res:
        node_data = kg_server.record2properties(record)
        # print(node_data)
        data['data']['nodes'].append(node_data)
        # print(data)
    if not data['data']['nodes']:
        data['code'] = 3
        data['msg'] = '没有查询到相关数据'
    logger.info(cypter_str)
    return jsonify(data)

@app.route('/kg/relation/query',methods=['POST'])
def kg_relation_query():
    """
            边查询
            ---
            tags:
              - 相关查询接口
            consumes:
              - "multipart/form-data"
            produces:
              - "application/json"
            parameters:
              - name: "relation_type"
                in: "formData"
                description: "关系类型"
                required: false
                type: "Array"
              - name: "limit"
                in: "formData"
                description: "查询条数"
                required: false
                type: "string"
              - name: "page"
                in: "formData"
                description: "页数---page和pagesize参数需要同时存在,否则只显示limit限制"
                required: false
                type: "string"
              - name: "pagesize"
                in: "formData"
                description: "每页显示条数---page和pagesize参数需要同时存在,否则只显示limit限制"
                required: false
                type: "string"
            responses:
              1:
                  description: 查询成功


                  example: {'code':1,
                            'message':Success',
                            'data':{
                              'nodes':[{
                                'k1':v1,
                                'k2':v2,
                                ...
                              }],
                              'edges':[]
                              }
                            }
              2:
                description: 查询失败,缺少有效的参数
              3:
                description: 查询失败,语法错误
              4:
                description: 没有匹配数据
            """
    data = {
        'code': 1,
        'msg': 'Success',
        'data': {
            'nodes': [],
            'edges': []
        }
    }

    kg_server = KGServer()
    form_data = request.form.to_dict()
    relation_type = form_data.get('relation_type')
    limit = form_data.get('limit') if form_data.get('limit') else '25'
    if 'page' and 'pagesize' in form_data:
        page = form_data.get('page')
        pagesize = form_data.get('pagesize')
        if page.isdigit() and pagesize.isdigit():
            if page == "1":
                paging_cmd = "SKIP 0 LIMIT {pagesize}".format(pagesize=pagesize)

            else:
                paging_cmd = "SKIP {num} LIMIT {pagesize}".format(num=(int(page)-1) * int(pagesize), pagesize=pagesize)
        else:
            data['code'] = 2
            data['msg'] = 'page/pagesize 必须为数字'
            return jsonify(data)
    else:
        paging_cmd = "LIMIT {limit}".format(limit=limit)

    if not relation_type:
        cypter_str = "MATCH p=()-->() RETURN p {paging_cmd}".format(paging_cmd=paging_cmd)
    else:
        try:
            relation_type = json.loads(relation_type)
            arg = '|'.join(relation_type)
            cypter_str = "MATCH p=()-[r:{arg}]->() RETURN p {paging_cmd}".format(arg=arg, paging_cmd=paging_cmd)
        except Exception as e:
            data['code'] = 2
            data['msg'] = "关系类型参数必须为数组"+str(e)
            logger.error(e)
            return jsonify(data)
    try:
        res = kg_server.select(cypter_str)
    except Exception as e:
        data['code'] = 2
        data['msg'] = str(e)
        logger.error(e)
        return jsonify(data)

    for rel in res:
        rel_data = kg_server.rel2properties(rel)
        data['data']['edges'].append(rel_data)
    if not data['data']['edges']:
        data['code'] = 3
        data['msg'] = '没有查询到相关数据'
    logger.info(cypter_str)
    return jsonify(data)

@app.route('/kg/path/query',methods=['POST'])
def kg_path_query():
    """
            路经查询
            ---
            tags:
              - 相关查询接口
            consumes:
              - "multipart/form-data"
            produces:
              - "application/json"
            parameters:
              - name: "start_node_uuid"
                in: "formData"
                description: "开始节点uuid"
                required: true
                type: "string"
              - name: "end_node_uuid"
                in: "formData"
                description: "结束节点uuid"
                required: true
                type: "string"
              - name: "level"
                in: "formData"
                description: "查询的最大跳数"
                required: false
                type: "string"
            responses:
              1:
                  description: 查询成功


                  example: {'code':1,
                            'message':Success',
                            'data':{
                              'nodes':[{
                                'k1':v1,
                                'k2':v2,
                                ...
                              }],
                              'edges':[]
                              }
                            }
              2:
                description: 查询失败,缺少有效的参数
              3:
                description: 查询失败,语法错误
              4:
                description: 没有匹配数据
            """
    data = {
        'code': 1,
        'msg': 'Success',
        'data': {
            'nodes': [],
            'edges': []
        }
    }
    if not request.form or not request.form.get('start_node_uuid') or not request.form.get('end_node_uuid'):
        data['code'] = 2
        data['msg'] = '缺少有效的参数'
        return jsonify(data)
    kg_server = KGServer()
    form_data = request.form.to_dict()
    st_node_uuid = form_data.get('start_node_uuid')
    en_node_uuid = form_data.get('end_node_uuid')
    level = form_data.get('level') if form_data.get('level') else '1'
    cypter_str = "MATCH p=(s {uuid:'%s'})-[*..%s]-(e {uuid:'%s'}) RETURN p"%(st_node_uuid, level, en_node_uuid)
    print(cypter_str)
    try:
        res = kg_server.select(cypter_str)
    except Exception as e:
        data['code'] = 2
        data['msg'] = str(e)
        logger.error(e)
        return jsonify(data)
    data_obj = res.data()
    if data_obj:
        rel_l = data_obj[0]['p'].relationships
        node_l = data_obj[0]['p'].nodes

        for rel in rel_l:
            data['data']['edges'].append(kg_server.rel_handel(rel))
        for node in node_l:
            data['data']['nodes'].append(kg_server.node_handel(node))
    if not data['data']['edges']:
        data['code'] = 3
        data['msg'] = '没有查询到相关数据'
    logger.info(cypter_str)
    return jsonify(data)

@app.route('/kg/graph/query',methods=['POST'])
def kg_graph_query():
    """
            局部图查询
            ---
            tags:
              - 相关查询接口
            consumes:
              - "multipart/form-data"
            produces:
              - "application/json"
            parameters:
              - name: "start_node_uuid"
                in: "formData"
                description: "开始节点uuid"
                required: true
                type: "string"
              - name: "relation_type"
                in: "formData"
                description: "关系类型"
                required: false
                type: "Array"
              - name: "level"
                in: "formData"
                description: "查询的最大跳数"
                required: false
                type: "string"
            responses:
              1:
                  description: 查询成功


                  example: {'code':1,
                            'message':Success',
                            'data':{
                              'nodes':[{
                                'k1':v1,
                                'k2':v2,
                                ...
                              }],
                              'edges':[]
                              }
                            }
              2:
                description: 查询失败,缺少有效的参数
              3:
                description: 查询失败,语法错误
              4:
                description: 没有匹配数据
            """
    data = {
        'code': 1,
        'msg': 'Success',
        'data': {
            'nodes': [],
            'edges': []
        }
    }
    if not request.form or not request.form.get('start_node_uuid'):
        data['code'] = 2
        data['msg'] = '缺少有效的参数'
        return jsonify(data)
    kg_server = KGServer()
    form_data = request.form.to_dict()
    st_node_uuid = form_data.get('start_node_uuid')
    level = form_data.get('level') if form_data.get('level') else '1'
    relation_type = form_data.get('relation_type')
    if relation_type:
        try:
            args = '|'.join(json.loads(relation_type))
            cypter_str = "MATCH p=(s {uuid:'%s'})-[r:%s*..%s]-() RETURN p"%(st_node_uuid, args, level)
        except Exception as e:
            data['code'] = 2
            data['msg'] = str(e)
            logger.error(e)
            return jsonify(data)
    else:
        cypter_str = "MATCH p=(s {uuid:'%s'})-[*..%s]-() RETURN p"%(st_node_uuid, level)

    try:
        # print(cypter_str)
        res = kg_server.select(cypter_str)
    except Exception as e:
        data['code'] = 2
        data['msg'] = str(e)
        logger.error(e)
        return jsonify(data)
    data_obj = res.data()
    if data_obj:
        for path in data_obj:
            rel_l = path['p'].relationships
            node_l = path['p'].nodes

            for rel in rel_l:
                data['data']['edges'].append(kg_server.rel_handel(rel))
            for node in node_l:
                ret = kg_server.node_handel(node)
                if ret not in data['data']['nodes']:
                    data['data']['nodes'].append(ret)
    if not data['data']['edges']:
        data['code'] = 3
        data['msg'] = '没有查询到相关数据'
    logger.info(cypter_str)
    return jsonify(data)


@app.route('/kg/node/batch/insert',methods=['POST'])
def kg_node_batch_insert():
    data = {
        'code': 1,
        'msg': 'Success',
        'data': {
            'nodes': [],
            'edges': []
        }
    }
    kg_server = KGServer()
    re_data = json.loads(request.data.decode("utf-8"))
    nodes_data = re_data['data']
    try:
        for node_data in nodes_data:
            label = node_data.pop('label')
            uuid = node_data.get('uuid')
            node_data['created_time'] = dt.now().strftime("%Y-%m-%d %X")
            if kg_server.node_is_exist(uuid):
                data['msg'] = '该节点uuid已经存在,不能重复创建'
                data['code'] = 2
                return jsonify(data)
            args = kg_server.dic2args(node_data)
            cypter_str = "CREATE (n:{label} {args}) return n".format(label=label, args=args)
            res = kg_server.create_node(cypter_str)
            if res:
                data['data']['nodes'].append(res)
                logger.info(cypter_str)
    except Exception as e:
        data['msg'] = str(e)
        data['code'] = 2
        return jsonify(data)
    return jsonify(data)


@app.route('/kg/edge/batch/insert',methods=['POST'])
def kg_edge_batch_insert():
    data = {
        'code': 1,
        'msg': 'Success',
        'data': {
            'nodes': [],
            'edges': []
        }
    }
    kg_server = KGServer()
    re_data = json.loads(request.data.decode("utf-8"))
    edges_data = re_data['data']
    try:
        for edge_data in edges_data:
            st_uuid = edge_data.pop('start_node_uuid')
            en_uuid = edge_data.pop('end_node_uuid')
            rel_type = edge_data.pop('relation_type')
            edge_data['created_time'] = dt.now().strftime("%Y-%m-%d %X")
            args = kg_server.dic2args(edge_data)
            if kg_server.node_is_exist(st_uuid) and kg_server.node_is_exist(en_uuid):
                rel_data = kg_server.rel_is_exist(st_uuid, en_uuid, rel_type)
                if rel_data:
                    data['code'] = 2
                    data['msg'] = '已存在关系'
                    return jsonify(data)
                else:
                    # print(st_uuid,en_uuid,rel_type,args)
                    cypter_str = "MATCH (s),(e) WHERE s.uuid='%s' AND e.uuid='%s' CREATE (s)-[r:%s %s] ->(e) RETURN r" % (
                        st_uuid, en_uuid, rel_type, args
                    )
                    rel_data = kg_server.create_rel(cypter_str)
                    rel_data['start_node_uuid'] = st_uuid
                    rel_data['end_node_uuid'] = en_uuid
                    data['data']['edges'].append(rel_data)
            else:
                data['msg'] = '起始节点或结束节点不存在'
                data['code'] = 2
                return jsonify(data)
    except Exception as e:
        data['msg'] = str(e)
        data['code'] = 2
        return jsonify(data)
    return jsonify(data)


@app.route('/update',methods=['POST'])
def update():
    kg_server = KGServer()
    form_data = request.form.to_dict()
    ID = form_data.pop('ID')
    node_type = form_data.pop('node_type')
    cmd = "MATCH (n:%s {%sID:'%s'}) return n"%(node_type,node_type,ID)
    node_obj = kg_server.select(cmd).data()
    node_pro_dic = dict(node_obj[0]['n'].items())
    for k,v in form_data.items():
        node_pro_dic[k] = v
    args = kg_server.dic2args(node_pro_dic)
    cypher_change_pro_cmd = "MATCH (n:%s {%sID:'%s'}) SET n=%s RETURN n"%(node_type,node_type,ID,args)
    res = kg_server.select(cypher_change_pro_cmd).data()
    if res:
        return jsonify('ok')


if __name__ == '__main__':
    app.run("0.0.0.0",5000,debug=True)
